from utils import singleton


@singleton
class EventBus:
    def __init__(self):
        self._topic_queue = {"default": []}
        self._fan_out_queue = []

    def register_topic(self, topic="default", handler=None):
        if handler is None:
            return
        if topic in self._topic_queue:
            self._topic_queue.get(topic).append(handler)
        else:
            self._topic_queue.update({topic: [handler]})

    def unregister_topic(self, topic="default", handler=None):
        if handler is None:
            return
        if topic in self._topic_queue:
            self._topic_queue.get(topic).remove(handler)
        if len(self._topic_queue.get(topic)) == 0:
            self._topic_queue.pop(topic)

    def register_fan_out(self, handler=None):
        if handler is None:
            return
        self._fan_out_queue.append(handler)

    def unregister_fan_out(self, handler=None):
        if handler is None:
            return
        self._fan_out_queue.remove(handler)

    def post_topic(self, event, topic="default"):
        dead_handlers = []
        if topic in self._topic_queue:
            for handler in self._topic_queue.get(topic):
                if callable(handler):
                    handler(event)
                else:
                    dead_handlers.append(handler)
        for h in dead_handlers:
            self._topic_queue.get(topic).remove(h)

    def post_fan_out(self, event):
        dead_handler = []
        for handler in self._fan_out_queue:
            if callable(handler):
                handler(event)
            else:
                dead_handler.append(handler)
        for h in dead_handler:
            self._fan_out_queue.remove(h)
